package nz.co.senanque.vaadinsupport.application;

import java.util.concurrent.atomic.AtomicLong;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.context.support.XmlWebApplicationContext;

import com.vaadin.Application;

/**
 * This is a helper class that loads the local Spring context for the Vaadin application.
 * It also acts as a factory bean for the application class which is already instantiated by Vaadin.
 * Much of the code is cloned over from Archie Cobbs {@linkplain org.dellroad.stuff.vaadin.SpringContextApplication}
 * @see <a href="http://dellroad-stuff.googlecode.com/">The dellroad-stuff Project</a>
 * The reason for not using Archie's technique directly is that it requires us to extend his
 * application class and Vaadin's touchkit requires us to extend a different class. So the bits
 * I need are delegated to this helper class where I can use them from any flavour of the Application
 * class.
 * @author Roger Parkinson
 *
 */
public class SpringApplicationLoader {
	
    private static final AtomicLong UNIQUE_INDEX = new AtomicLong();
    private static Logger log = LoggerFactory.getLogger(SpringApplicationLoader.class);
    private static final ThreadLocal<Application> CURRENT_APPLICATION = new ThreadLocal<Application>();

    public static ApplicationContext loadContext(Application application, HttpServletRequest request) {

        // Logging
        log.info("loading application context for Vaadin application " + application.getClass().getSimpleName());
        CURRENT_APPLICATION.set(application);

        // Find the application context associated with the servlet; it will be the parent
        ServletContext servletContext;
        try {
            // getServletContext() is a servlet AIP 3.0 method, so don't freak out if it's not there
            servletContext = (ServletContext)HttpServletRequest.class.getMethod("getServletContext").invoke(request);
        } catch (Exception e) {
            servletContext = ContextLoader.getCurrentWebApplicationContext().getServletContext();
        }
        WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(servletContext);

        // Create and configure a new application context for this Application instance
        ConfigurableWebApplicationContext context = new XmlWebApplicationContext();
        context.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX
          + servletContext.getContextPath() + "/" + application.getClass().getSimpleName() + "-"
          + UNIQUE_INDEX.incrementAndGet());
        context.setParent(parent);
        context.setServletContext(servletContext);
        //context.setServletConfig(??);
        context.setNamespace(application.getClass().getSimpleName());

        // Refresh context
        context.refresh();
        
        CURRENT_APPLICATION.set(null);
        return context;
    }
    public Application get()
    {
    	return CURRENT_APPLICATION.get();
    }
}
